package com.zhouyu.fileSync.FSclient.InvocationHandlers;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zhouyu.fileSync.FScommon.api.RpcNettyClient;
import com.zhouyu.fileSync.FScommon.api.entities.MessageType;
import com.zhouyu.fileSync.FScommon.api.entities.Request;
import com.zhouyu.fileSync.FScommon.api.entities.Response;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * invoke the rpc method
 * use netty to send an receive message
 */
public class RpcInvocationHandler implements InvocationHandler {

    private Object targetObject;
    private RpcNettyClient rnc;

    public Object newProxyInstance(Object targetObject, RpcNettyClient rnc) {
        this.targetObject = targetObject;
        this.rnc=rnc;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equalsIgnoreCase("toString")) {
           return null;
        }
        Request request = new Request();
        request.setClassName(method.getDeclaringClass().getName());
        request.setMethodName(method.getName());
        request.setParameters(args);
        request.setParameterTypes(method.getParameterTypes());
        request.setRequestId(UUID.randomUUID().toString());
        request.setMessageType(MessageType.METHOD);
        Response response = rnc.sendToServer(request);
        Class<?> returnType = method.getReturnType();

        if (response.getCode() == 1) {
            throw new Exception(response.getErrorMsg());
        }
        if (response.getData()!=null) {
            if (returnType.isPrimitive() || String.class.isAssignableFrom(returnType) || response.getData().getClass().isAssignableFrom(returnType)) {
                return response.getData();
            } else if (Collection.class.isAssignableFrom(returnType)) {
                return JSONArray.parseArray(response.getData().toString(), Object.class);
            } else if (Map.class.isAssignableFrom(returnType)) {
                return JSON.parseObject(response.getData().toString(), Map.class);
            } else {
                Object data = response.getData();
                return JSONObject.parseObject(data.toString(), returnType);
            }
        }else {
            return null;
        }
    }
}
